package uage.ast

import scala.collection.mutable.MapBuilder
import scala.collection.mutable.ListBuffer
import scala.collection.Map
import scala.collection.Parallel
import java.util.logging.Logger
import scala.collection.mutable.Queue

import uage.exception._
import uage.logger.logger

abstract class Expr() {
  def eval() = this
}

case object nil extends Expr{
  override def toString() = "nil"
}

object Identifier {
  val NUMBER = -17
  val STRING = -18
  val SYMBOL = -19
  
  val ASSIGN = -22        // =
  //Arithmetic operator
  val PLUS = -23           // +
  val SUBTRACT = -24      // -
  val MULTIPLY = -25      // * 
  val DIVIDE = -26        // /
  val REMAINDER = -27     // %
  val PLUSPLUS = -28          //++
  val SUBSUB = -29          //--
  
  //Relation operator
  val EQUAL = -33          // ==
  val UNEQUAL = -34        // !=
  val MORE_THAN = -35      // >
  val LESS_THAN = -36      // <
  val NO_MORE_THAN = -37   // <=
  val NO_LESS_THAN = -38   // >=
  
  //Logical operator
  val AND = -44            // &&
  val OR = -45             // ||
  val NOT = -46            // !
  
  //other operator
  val LEFT_ARROW = -55     // <-
  val RIGHT_ARROW = -56    // ->
  val EQUAL_ARROW = -57    // =>
  val DOUBT = -58          // ?
  
  val BEGIN_PAREN = -101 //e.g. id (
  val BEGIN_BRACE = -102 //e.g. id { or () {
  
  
  /**
   * Operator precedence
   */
  object weight {
    
    val ASSIGN = 10  // = 
    
		val OR = 11  // || 
		val AND = 12  // &&
		
		val EQUAL = 15  // ==
		val UNEQUAL = 15  // !=
		val MORE_THAN = 15  // >
		val LESS_THAN = 15  // <
		val NO_MORE_THAN = 15  // <=
		val NO_LESS_THAN = 15  // >=
		
    val ADD = 17
    val SUBTRACT = 17
    val MULTIPLY = 27
    val DIVIDE = 27
    val REMAINDER = 27
    
//    val NOT = 28
//    val PLUSPLUS = 29
//    val SUBSUB = 29
    
    
    
    val map = Map((SymbolExpr("="),ASSIGN),(SymbolExpr("+"),ADD),
        (SymbolExpr("-"),SUBTRACT),(SymbolExpr("*"),MULTIPLY),
        (SymbolExpr("/"),DIVIDE),(SymbolExpr("%"),REMAINDER),
        (SymbolExpr("=="),EQUAL),(SymbolExpr("!="),UNEQUAL),
        (SymbolExpr(">"),MORE_THAN),(SymbolExpr("<"),LESS_THAN),
        (SymbolExpr(">="),NO_LESS_THAN),(SymbolExpr("<="),NO_MORE_THAN),
        (SymbolExpr("=="),EQUAL),(SymbolExpr("!="),UNEQUAL),
        (SymbolExpr("&&"),AND),(SymbolExpr("||"),OR))
//        (SymbolExpr("!"),NOT),(SymbolExpr("++"),PLUSPLUS),(SymbolExpr("--"),SUBSUB))
    def get(op:SymbolExpr):Int = {
      map.getOrElse(op, 0)
    }
  }
  /**
   * if op a operator
   */
  def isOperator(op:SymbolExpr):Boolean = {
    if(Identifier.weight.map.contains(op)){
      true
    } else {
      false
    }
    
  }
}

//true and false 
case object truexpr extends Expr
case object falsexpr extends Expr

//*********************some extra info stored in nodes***********************//
//implemented closure
case object closure extends Expr
case class ClosureMap(var elems:scala.collection.mutable.Map[Expr,Expr]) extends Expr

//call and definition parameter map
case object parambinding extends Expr
case class ParamBindingMap(var elems:Map[Expr,Expr]) extends Expr

//
case object operator extends Expr
case class OperatorMap(var elems:scala.collection.mutable.Set[Expr]) extends Expr

//primary invoke
case object classmanager extends Expr
case class ClassManagerMap(var elems:scala.collection.mutable.Map[Any,Any]) extends Expr {
}
//**************************************************************************//
case class ClassExpr(var clazz:Class[_],var obj:Any) extends Expr {
  override def toString = obj.toString()
}

case class ChainExpr() extends Expr {
  var list = ListBuffer[Expr]()  //invoke chain
  //var tail:Expr = nil //the target expr(the last of list)  e.g. a.b.c  means c
  var pointer:Expr = nil //where list(-1) stayed in  e.g. a.b.c means a
}

//*****************************if sentence*************************//
case class IfExpr(var cond:Expr) extends Expr{
  var exprT:Expr = nil //true
  var exprF:Expr = nil //false
}
//******************************************************************//

//*****************************if sentence*************************//
case class ForExpr(var cond:Expr) extends Expr{
  var expr:Expr = nil
}
//******************************************************************//
case class AssignExpr(var left:Expr,var right:Expr) extends Expr {
  override def toString = left + " = " + right
}

case class DotExpr(var expr1:Expr,var expr2:Expr) extends Expr {
  var parent:Expr = nil
  override def toString  = expr1 + "." + expr2
}

case class SymbolExpr(var symbol:String) extends Expr {
  def toParamExpr = ParamExpr(symbol)
  def toStringExpr = StringExpr(symbol)
  override def toString = symbol
}

case class ParamExpr(var param:String) extends Expr {}

case class StringExpr(var value:String) extends Expr {
  override def eval() = StringExpr(value) //返回另一个对象
  def toSymbolExpr = SymbolExpr(value)
  override def toString = "\"" + value + "\""
}

case class NumberExpr(var value:Double) extends Expr {
  override def eval() = NumberExpr(value) ////返回另一个对象
  override def toString() = value.toString()
}

case class ReturnExpr(var value:Expr) extends Expr {
  override def eval() = value
}

case class MapExpr() extends Expr {
  var elems = scala.collection.mutable.Map[Expr,Expr]()
}

case class ListExpr(var elems:ListBuffer[Expr]) extends Expr {
  override def toString = elems.mkString("[",", ","]")
}

case class TupleExpr(var elems : ListBuffer[Expr]) extends Expr {
  override def toString() = elems.mkString("(", ", ", ")")
}

case class PairExpr(var key:Expr,var value:Expr) extends Expr {
  override def eval() = value.eval()
  override def toString() = key + ": " + value
}

case class UnitExpr(var list:List[Expr]) extends Expr {}

case class FieldExpr(var key:SymbolExpr,var value:Expr) extends Expr {}

case class OperatorExpr(var op:SymbolExpr,var left:Expr,var right:Expr) extends Expr {
  override def toString() = left + " " + op + " " + right
}

case class InvokeExpr(var symbol:Expr,var params:ListBuffer[Expr]) extends Expr {
  override def toString = symbol + params.mkString("(", ", ", ")")
}

case class GraphExpr() extends Expr {
  var parent:GraphExpr = null //parent node
  var params = ListBuffer[Expr]()
  val nodes = scala.collection.mutable.Map[Expr,Expr]() //inner graph
  var exprStream:ListBuffer[Expr] = ListBuffer();
  override def toString():String = {
    val paramsInfo = params.mkString("(", ", ", ")")
    val nodesInfo = nodes.mkString(" ")
    val exprStringInfo = exprStream.mkString(" ")
    if(nodesInfo.trim() == ""){
      return paramsInfo + "{" + exprStringInfo + "}"
    } else if(exprStringInfo.trim() == ""){
      return paramsInfo + "{" + nodesInfo + "}"
    } else {
    	return paramsInfo + "{" + nodesInfo + " " + exprStringInfo + "}"
    }
  }
  
  override def eval():Expr = {
    logger.info(this,"eval", null)
    var caches = scala.collection.mutable.Map[Expr,Expr]() //local variable symbol table
    
    //put arguments in the caches when invoking an object
    var map = this.nodes.getOrElse(parambinding, nil)
    if(map != nil){
      map.asInstanceOf[ParamBindingMap].elems.foreach(pair => {
        caches.put(pair._1, pair._2)
      })
      //clear param and arg binding
      this.nodes.put(parambinding, nil)
    }
    var rst:Expr = nil
    exprStream.foreach(expr=>{
      rst = evalExpr(caches, expr)
      if(rst.isInstanceOf[ReturnExpr]){
        return rst.asInstanceOf[ReturnExpr].value
        //return rst
      }
    })
    
    rst
  }
  
  def copy() = {
    this.clone().asInstanceOf[GraphExpr]
  }
  
  /**
   * initialize graph before func eval runs
   */
  def init() = {
    logger.info(this, "init", null)
    this.nodes.foreach(child =>{
      if(child._2.isInstanceOf[SymbolExpr]){ //e.g. a:b
        nodes.put(child._1, this.getNode(child._2.asInstanceOf[SymbolExpr]))
      }
    })
  }
  
  def contains(symbol:Expr):Boolean = {
    //logger.info(this, "contains", List(symbol))
    var rst = false
    if(nodes.contains(symbol)){
      rst = true
    } else if(this.parent != null && this.parent.contains(symbol)){
       rst = true
    }
    rst
  }
  
  /**
   * find a expr represents by symbol
   */
  def getNode(symbol:Expr):Expr = {
    //logger.info(this, "getNode", List(symbol))
    var elem:Expr = this.nodes.getOrElse(symbol, nil)
//    if(elem == nil && this.nodes.getOrElse(closure, nil) != nil){ //find in closure
//      elem = this.nodes.getOrElse(closure, nil).asInstanceOf[ClosureMap].elems.getOrElse(symbol, nil)
//    } 
    if(elem == nil && this.parent != null){ //find in parent
      elem = this.parent.getNode(symbol)
    }
    return elem
  }
  
  /**
   * set the value of symbol to expr
   */
  def setNode(symbol:Expr,expr:Expr):Unit = {
    //logger.info(this, "setExpr", List(symbol,expr))
    if (nodes.contains(symbol)){
      nodes.put(symbol, expr)
    } else if(this.parent != null){
      this.parent.setNode(symbol, expr)
    } else { //if it does't exist
      throw ExprNotFoundException(symbol)
    }
  }
  
  /**
   * find a expr represents by symbol include closure
   */
  def searchNode(symbol:Expr):Expr = {
    //logger.info(this, "getNode", List(symbol))
    var elem:Expr = this.nodes.getOrElse(symbol, nil)
    if(elem == nil && this.nodes.getOrElse(closure, nil) != nil){ //find in closure
      elem = this.nodes.getOrElse(closure, nil).asInstanceOf[ClosureMap].elems.getOrElse(symbol, nil)
    } 
    if(elem == nil && this.parent != null){ //find in parent
      elem = this.parent.searchNode(symbol)
    }
    return elem
  }
  
  /**
   * find expr from caches first,then call getNode
   */
  def findExpr(caches:scala.collection.mutable.Map[Expr,Expr],symbol:Expr):Expr = {
    var expr = caches.getOrElse(symbol, nil)
    if(expr == nil){
      expr = this.searchNode(symbol)
    }
    expr
  }
  
  /**
   * function as an operator
   */
  def asOperator() = {
    
  }
  
  def evalClassExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
//    if(!expr.isInstanceOf[ClassExpr]) throw ExprTypeMismatchException(expr)
//    var classExpr = expr.asInstanceOf[ClassExpr]
    expr
    
  }
  
  // instance = fromClass("java.io.String")
  def evalFromClassExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    if(!expr.isInstanceOf[StringExpr]) throw ExprTypeMismatchException(expr)
    var clazz = Class.forName(expr.asInstanceOf[StringExpr].value)
    var obj = clazz.newInstance()
    return ClassExpr(clazz,obj)
  }
  
  //eval expr cond
  def evalCond(cond:Expr):Boolean = {
    if(cond == nil || cond == falsexpr){ //nil or false is false
      return false
    } else if(cond.isInstanceOf[NumberExpr]){ //negative num is false
      return cond.asInstanceOf[NumberExpr].value > 0
    } else if(cond.isInstanceOf[StringExpr]){
      var str = cond.asInstanceOf[StringExpr]
      return (str.value.length() != 0 //empty string is false
          && str.value != "false")
    } else {
      return true
    }
  }
  
  def evalForExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    if(!expr.isInstanceOf[ForExpr]) throw ExprTypeMismatchException(expr)
    var forExpr = expr.asInstanceOf[ForExpr]
    
    var cond = this.evalCond(this.evalExpr(caches, forExpr.cond))
    var rstList = ListBuffer[Expr]()
    while(cond){
      rstList.append(this.evalExpr(caches, forExpr.expr))
      cond = this.evalCond(this.evalExpr(caches, forExpr.cond))
    }
    return ListExpr(rstList)
  }
  
  def evalIfExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    if(!expr.isInstanceOf[IfExpr]) throw ExprTypeMismatchException(expr)
    var ifExpr = expr.asInstanceOf[IfExpr]
    
    var cond = this.evalCond(this.evalExpr(caches, ifExpr.cond))
    if(cond){
      evalExpr(caches, ifExpr.exprT)
    }else{
      evalExpr(caches, ifExpr.exprF)
    }
  }
  
  def evalListExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    var list:ListBuffer[Expr] = null
    if(expr.isInstanceOf[TupleExpr]){
    	list = expr.asInstanceOf[TupleExpr].elems
    } else if(expr.isInstanceOf[ListExpr]){
      list = expr.asInstanceOf[ListExpr].elems
    } else {
      throw ExprTypeMismatchException(expr)
    }
    if(list.length == 1){ //eval it's value e.g. (3+2) || (a) || (3)
      if(list(0).isInstanceOf[GraphExpr]){ //return graph directly
        return list(0)
      } else {
    	  return evalExpr(caches, list(0))
      }
    }
    var rst = ListBuffer[Expr]()
    list.foreach(elem =>{
      if(elem.isInstanceOf[GraphExpr]){ //return graph directly
        rst.append(elem)
      } else {
    	  rst.append(evalExpr(caches, elem))
      }
    })
    return ListExpr(rst)
  }
  
//  def evalDotExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
//    if(!expr.isInstanceOf[DotExpr]) throw throw ExprTypeMismatchException("Want DotExpr,found: " + expr)
//    var dot = expr.asInstanceOf[DotExpr]
//    dot.expr1 match {
//      case _:SymbolExpr => { //e.g. a.b...
//        dot.parent = this.findExpr(caches, dot.expr1)
//        if(dot.parent == nil) throw ExprNotFoundException(dot.expr1)
//        if(dot.parent.isInstanceOf[TupleExpr]){
//          if(dot.expr2.isInstanceOf[TupleExpr]){ //e.g. b = (a,b,c) b.1
//            var symbol = this.evalExpr(caches, dot.expr2)
//            if(!symbol.isInstanceOf[NumberExpr]) throw SyntaxException(symbol)
//            var rst = dot.parent.asInstanceOf[TupleExpr].elems(symbol.asInstanceOf[NumberExpr].value.intValue())
//            if(rst == nil) throw ExprNotFoundException(dot.expr2)
//            return rst
//          } else { //e.g. tuple = (a,b,c,...) tuple.1
//            if(!dot.expr2.isInstanceOf[NumberExpr]) throw SyntaxException(dot.expr2)
//            var rst = dot.parent.asInstanceOf[TupleExpr].elems(dot.expr2.asInstanceOf[NumberExpr].value.intValue())
//            if(rst == nil) throw ExprNotFoundException(dot.expr2)
//            return rst
//          }
//        }
//        if(dot.parent.isInstanceOf[ListExpr]){
//          var parent = dot.parent.asInstanceOf[ListExpr]
//          if(dot.expr2.isInstanceOf[TupleExpr]){ //e.g. b = [a,b,c] i = 1 b.(i)
//            var symbol = this.evalExpr(caches, dot.expr2)
//            if(!symbol.isInstanceOf[NumberExpr]) throw SyntaxException(symbol)
//            var rst = dot.parent.asInstanceOf[ListExpr].elems(symbol.asInstanceOf[NumberExpr].value.intValue())
//            if(rst == nil) throw ExprNotFoundException(dot.expr2)
//            return rst
//          } else if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. list.first()
//            var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
//            invokeExpr.symbol match {
//              case SymbolExpr("first") => { //e.g. list.first()
//                if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
//                return parent.elems(0)
//              }
//              case SymbolExpr("last") => { //e.g. list.last()
//                if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
//                return parent.elems(parent.elems.length-1)
//              }
//              case SymbolExpr("takeFirst") => { //e.g. list.first()
//                if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
//                return parent.elems.remove(0)
//              }
//              case SymbolExpr("takeLast") => { //e.g. list.last()
//                if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
//                return parent.elems.remove(parent.elems.length-1)
//              }
//              case SymbolExpr("putFirst") => { //e.g. list.putHead(1)
//                if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
//                parent.elems.prepend(invokeExpr.params(0))
//                return nil
//              }
//              case SymbolExpr("putLast") => { //e.g. list.putBack(9)
//                if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
//                parent.elems.append(invokeExpr.params(0))
//                return nil
//              }
//              case SymbolExpr("get") => { //e.g. list.get(0)
//                if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
//                if(!invokeExpr.params(0).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.get(),Want number,found: " + invokeExpr.params(0))
//                return parent.elems(invokeExpr.params(0).asInstanceOf[NumberExpr].value.intValue())
//              }
//              case SymbolExpr("take") => { //e.g. list.take(0)
//                if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
//                if(!invokeExpr.params(0).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.take(),Want number,found: " + invokeExpr.params(0))
//                return parent.elems.remove(invokeExpr.params(0).asInstanceOf[NumberExpr].value.intValue())
//              }
//              case SymbolExpr("insert") => { //e.g. list.insert(0,2)
//                if(invokeExpr.params.length != 2) throw ParamLengthMismatchException("list: " + invokeExpr)
//                if(!invokeExpr.params(0).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.take(),Want number,found: " + invokeExpr.params(0))
//                //if(!invokeExpr.params(1).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.take(),Want number,found: " + invokeExpr.params(1))
//                parent.elems.insert(invokeExpr.params(0).asInstanceOf[NumberExpr].value.intValue(), invokeExpr.params(1))
//                return nil
//              }
//              case other => {
//                throw ExprNotFoundException(other)
//              }
//            }
//          } else { //e.g. tuple = (a,b,c,...) tuple.1
//            if(!dot.expr2.isInstanceOf[NumberExpr]) throw SyntaxException(dot.expr2)
//            var rst = dot.parent.asInstanceOf[ListExpr].elems(dot.expr2.asInstanceOf[NumberExpr].value.intValue())
//            if(rst == nil) throw ExprNotFoundException(dot.expr2)
//            return rst
//          }
//        }
//        if(!dot.parent.isInstanceOf[GraphExpr]) throw ExprNotCallableException(dot.parent) ////e.g. a = {b:3} a.b
//        if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. a.b()
//          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
//          var symbol = dot.parent.asInstanceOf[GraphExpr].getNode(invokeExpr.symbol)
//          return evalInvokeExpr(caches, InvokeExpr(symbol,invokeExpr.params))
//        } else if(dot.expr2.isInstanceOf[TupleExpr]){ //e.g. b = "name" a.(b) == a."name"
//          var symbol = this.evalExpr(caches, dot.expr2)
//          var rst = dot.parent.asInstanceOf[GraphExpr].getNode(symbol)
//          if(rst == nil) throw ExprNotFoundException(dot.expr2)
//          return rst
//        } else { //e.g. a.b
//          var rst = dot.parent.asInstanceOf[GraphExpr].getNode(dot.expr2)
//          if(rst == nil) throw ExprNotFoundException(dot.expr2)
//          return rst
//        }
//      }
//      case graph:GraphExpr => { //e.g. a = {b:3} a.b
//        dot.parent = graph
//        if(dot.expr2.isInstanceOf[InvokeExpr]){
//          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
//          var symbol = graph.getNode(invokeExpr.symbol)
//          return evalInvokeExpr(caches, InvokeExpr(symbol,invokeExpr.params))
//        } else {
//        	return graph.getNode(dot.expr2)
//        }
//      }
//      case invoke:InvokeExpr => {
//        dot.parent = evalInvokeExpr(caches, invoke)
//        if(!dot.parent.isInstanceOf[GraphExpr]) throw ExprNotCallableException(dot.parent)
//        if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. dotexpr.b()
//          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
//          var symbol = dot.parent.asInstanceOf[GraphExpr].getNode(invokeExpr.symbol)
//          return evalInvokeExpr(caches, InvokeExpr(symbol,invokeExpr.params))
//        } else {
//        	var rst = dot.parent.asInstanceOf[GraphExpr].getNode(dot.expr2)
//        	if(rst == nil) throw ExprNotFoundException(dot.expr2)
//        	return rst
//        }
//          
//      }
//      case dotExpr:DotExpr => {
//        dot.parent = evalDotExpr(caches, dotExpr)
//        if(dot.parent.isInstanceOf[ListExpr]) {
//          var listDotExpr = DotExpr(dot.parent,dotExpr.expr2)
//          return evalDotExpr(caches, listDotExpr)
//        }
//        if(!dot.parent.isInstanceOf[GraphExpr]) throw ExprNotCallableException(dot.parent)
//        if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. dotexpr.b()
//          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
//          var symbol = dot.parent.asInstanceOf[GraphExpr].getNode(invokeExpr.symbol)
//          return evalInvokeExpr(caches, InvokeExpr(symbol,invokeExpr.params))
//        } else {
//        	var rst = dot.parent.asInstanceOf[GraphExpr].getNode(dot.expr2)
//        	if(rst == nil) throw ExprNotFoundException(dot.expr2)
//        	return rst
//        }
//          
//      }
//      case other => {
//        throw SyntaxUnrealizedException(dot)
//      }
//    }
//    
//    nil
//  }
  
  def evalDotExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    if(!expr.isInstanceOf[DotExpr]) throw throw ExprTypeMismatchException("Want DotExpr,found: " + expr)
    var dot = expr.asInstanceOf[DotExpr]
    dot.expr1 match {
      case graph:GraphExpr => { //e.g. a = {b:3} a.b
        dot.parent = graph
        if(dot.expr2.isInstanceOf[InvokeExpr]){
          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
          var symbol = graph.getNode(invokeExpr.symbol)
          return evalInvokeExpr(caches, InvokeExpr(symbol,invokeExpr.params))
        } else if(dot.expr2.isInstanceOf[TupleExpr]){ //e.g. graph.(i)
          var symbol = this.evalExpr(caches, dot.expr2)
          return evalDotExpr(caches, DotExpr(graph,symbol))
        }else {
        	return graph.getNode(dot.expr2)
        }
      }
      
      case string:StringExpr => { //"some text"
        dot.parent = string
        if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. str.length()
          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
          var obj = string.value
          var methodName = invokeExpr.symbol.asInstanceOf[SymbolExpr].symbol
          var method = classOf[String].getMethod(methodName)
          var rst = method.invoke(obj)
        }
      }
      
      case tuple:TupleExpr => {
        dot.parent = tuple
        if(dot.expr2.isInstanceOf[TupleExpr]){ //e.g. a = 1 b.(a)
          var symbol = this.evalExpr(caches, dot.expr2)
          if(!symbol.isInstanceOf[NumberExpr]) throw SyntaxException(symbol)
          var rst = dot.parent.asInstanceOf[TupleExpr].elems(symbol.asInstanceOf[NumberExpr].value.intValue())
          if(rst == nil) throw ExprNotFoundException(dot.expr2)
          return rst
        } else { //e.g. tuple = (a,b,c,...) tuple.1
          if(!dot.expr2.isInstanceOf[NumberExpr]) throw SyntaxException(dot.expr2)
          var rst = dot.parent.asInstanceOf[TupleExpr].elems(dot.expr2.asInstanceOf[NumberExpr].value.intValue())
          if(rst == nil) throw ExprNotFoundException(dot.expr2)
          return rst
        }
      }
      
      case list:ListExpr => {
        dot.parent = list
        if(dot.expr2.isInstanceOf[TupleExpr]){ //e.g. b = [a,b,c] i = 1 b.(i)
          var symbol = this.evalExpr(caches, dot.expr2)
          if(!symbol.isInstanceOf[NumberExpr]) throw SyntaxException(symbol)
          var rst = list.elems(symbol.asInstanceOf[NumberExpr].value.intValue())
          if(rst == nil) throw ExprNotFoundException(dot.expr2)
          return rst
        } else if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. list.first()
          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
          invokeExpr.symbol match {
            case SymbolExpr("length") => { //e.g. list.length
              if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
              return NumberExpr(list.elems.length)
            }
            case SymbolExpr("first") => { //e.g. list.first()
              if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
              return list.elems(0)
            }
            case SymbolExpr("last") => { //e.g. list.last()
              if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
              return list.elems(list.elems.length-1)
            }
            case SymbolExpr("takeFirst") => { //e.g. list.first()
              if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
              return list.elems.remove(0)
            }
            case SymbolExpr("takeLast") => { //e.g. list.last()
              if(invokeExpr.params.length != 0) throw ParamLengthMismatchException("list: " + invokeExpr)
              return list.elems.remove(list.elems.length-1)
            }
            case SymbolExpr("putFirst") => { //e.g. list.putHead(1)
              if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
              list.elems.prepend(invokeExpr.params(0))
              return nil
            }
            case SymbolExpr("putLast") => { //e.g. list.putBack(9)
              if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
              list.elems.append(invokeExpr.params(0))
              return nil
            }
            case SymbolExpr("get") => { //e.g. list.get(0)
              if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
              if(!invokeExpr.params(0).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.get(),Want number,found: " + invokeExpr.params(0))
              return list.elems(invokeExpr.params(0).asInstanceOf[NumberExpr].value.intValue())
            }
            case SymbolExpr("take") => { //e.g. list.take(0)
              if(invokeExpr.params.length != 1) throw ParamLengthMismatchException("list: " + invokeExpr)
              if(!invokeExpr.params(0).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.take(),Want number,found: " + invokeExpr.params(0))
              return list.elems.remove(invokeExpr.params(0).asInstanceOf[NumberExpr].value.intValue())
            }
            case SymbolExpr("insert") => { //e.g. list.insert(0,2)
              if(invokeExpr.params.length != 2) throw ParamLengthMismatchException("list: " + invokeExpr)
              if(!invokeExpr.params(0).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.take(),Want number,found: " + invokeExpr.params(0))
              //if(!invokeExpr.params(1).isInstanceOf[NumberExpr]) throw ExprTypeMismatchException("list.take(),Want number,found: " + invokeExpr.params(1))
              list.elems.insert(invokeExpr.params(0).asInstanceOf[NumberExpr].value.intValue(), invokeExpr.params(1))
              return nil
            }
            case other => {
              throw ExprNotFoundException(other)
            }
          }
        } else { //e.g. tuple = (a,b,c,...) tuple.1
          if(!dot.expr2.isInstanceOf[NumberExpr]) throw SyntaxException(dot.expr2)
          var rst = list.elems(dot.expr2.asInstanceOf[NumberExpr].value.intValue())
          if(rst == nil) throw ExprNotFoundException(dot.expr2)
          return rst
        }
      }
      
      case classExpr:ClassExpr => {
        dot.parent = classExpr
        if(dot.expr2.isInstanceOf[InvokeExpr]){ //e.g. "string".length()
          var invokeExpr = dot.expr2.asInstanceOf[InvokeExpr]
          
          var classList:ListBuffer[Class[_]] = new ListBuffer[Class[_]] //param type
          var paramList:ListBuffer[Object] = new ListBuffer[Object] //param value
          invokeExpr.params.foreach(param => {
            param match {
              case num:NumberExpr => { //当作int类型处理
                classList.append(classOf[Int])
                paramList.append(num.value.intValue().asInstanceOf[Object])
              }
              case str:StringExpr => {
                classList.append(classOf[String])
                paramList.append(str.value.asInstanceOf[Object])
              }
              case c:ClassExpr => {
                classList.append(c.clazz)
                paramList.append(c.obj.asInstanceOf[Object])
              }
            }
          })
          var methodName = invokeExpr.symbol.asInstanceOf[SymbolExpr].symbol
          var method = classExpr.clazz.getMethod(methodName, classList.toArray:_*)
          var rst = method.invoke(classExpr.obj, paramList.toArray:_*)
          return ClassExpr(rst.getClass,rst)
        } else {
          throw ExprUnrealizedException(dot)
        }
        
      }
      
      case _:SymbolExpr => { //e.g. a.b...
        dot.parent = this.findExpr(caches, dot.expr1)
        if(dot.parent == nil) throw ExprNotFoundException(dot.expr1)
        return evalDotExpr(caches, DotExpr(dot.parent,dot.expr2))
      }
      
      case invoke:InvokeExpr => { //e.g. func().b
        dot.parent = evalInvokeExpr(caches, invoke)
        if(dot.parent == nil) throw ExprNotFoundException(dot.expr1)
        return evalDotExpr(caches, DotExpr(dot.parent,dot.expr2))
      }
      
      case dotExpr:DotExpr => {
        dot.parent = evalDotExpr(caches, dotExpr)
        if(dot.parent == nil) throw ExprNotFoundException(dot.expr1)
        return evalDotExpr(caches, DotExpr(dot.parent,dot.expr2))
      }
      case other => {
        throw SyntaxUnrealizedException(dot)
      }
    }
    
    nil
  }
  
  /**
   * e.g. a.b 
   */
  def evalChainExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    if(!expr.isInstanceOf[ChainExpr]) throw ExprTypeMismatchException("Want ChainExpr,found: " + expr)
    if(expr.asInstanceOf[ChainExpr].list.size < 2) throw ExprTypeMismatchException("ChainExpr.list:" + expr.asInstanceOf[ChainExpr].list)
    var chain = expr.asInstanceOf[ChainExpr]
    //chain.tail = chain.list(-1) //target expr
    var pointer  = this.findExpr(caches, chain.list(0)) //where target expr stayed in
    if(pointer == nil) throw ExprNotFoundException(expr)
    if(!pointer.isInstanceOf[GraphExpr]) throw SyntaxUnrealizedException(expr)
    chain.pointer = pointer
    if(chain.list.size == 2) return chain
    for(i <- Range(1,chain.list.size-2)){ //e.g. a.b.c.d means from b to c
      pointer = chain.pointer.asInstanceOf[GraphExpr].getNode(chain.list(i))
      if(pointer == nil) throw ExprNotFoundException(pointer)
    }
    return chain
  }
  
  def evalPairExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
    return expr    
  }
  
  /**
   * evaluate expression according to the type of expr
   */
  def evalExpr(caches:scala.collection.mutable.Map[Expr,Expr],expr:Expr):Expr = {
      var rst:Expr = nil
      if(expr.isInstanceOf[StringExpr] || expr.isInstanceOf[NumberExpr]){
        rst = expr.eval()
      }else if(expr.isInstanceOf[SymbolExpr]){ //find expr represent by symbol e.g. a + b, a + 3 , ...
        rst = this.findExpr(caches, expr)
      } else if(expr.isInstanceOf[AssignExpr]){
        rst = this.evalAssignExpr(caches, expr.asInstanceOf[AssignExpr])
      } else if(expr.isInstanceOf[OperatorExpr]){ //e.g. a + ( b + c)
        rst = evalOperatorExpr(caches,expr.asInstanceOf[OperatorExpr])
      } else if(expr.isInstanceOf[InvokeExpr]){ //e.g a + f(b)
        rst = evalInvokeExpr(caches,expr.asInstanceOf[InvokeExpr])
      } else if(expr.isInstanceOf[GraphExpr]){ //e.g. a = {...} || a() = {...}
        expr.asInstanceOf[GraphExpr].parent = this
        expr.asInstanceOf[GraphExpr].nodes.put(closure, ClosureMap(caches)) //closure
        rst = expr.eval()
      } else if(expr.isInstanceOf[DotExpr]){
        rst = evalDotExpr(caches, expr)
      } else if(expr.isInstanceOf[TupleExpr] || expr.isInstanceOf[ListExpr]){
        rst = evalListExpr(caches, expr)
      } else if(expr.isInstanceOf[IfExpr]){
        rst = evalIfExpr(caches, expr)
      } else if(expr.isInstanceOf[ForExpr]){
        rst = evalForExpr(caches, expr)
      } else if(expr.isInstanceOf[PairExpr]){
        rst = evalPairExpr(caches, expr)
      } else if(expr.isInstanceOf[ClassExpr]){
        rst = evalClassExpr(caches, expr)
      }else if(expr == nil){
        rst = nil
      }else {
        throw UnsupportedExprException(expr)
      }
      rst
      
    }
  
  def evalInvokeExpr(caches:scala.collection.mutable.Map[Expr,Expr],invokeExpr:InvokeExpr):Expr = {
      logger.info(this, "evalInvokeExpr", List(caches,invokeExpr))
      
      
      var expr:Expr = nil
      if(invokeExpr.symbol.isInstanceOf[GraphExpr]){ //call directly
        expr = invokeExpr.symbol
      }
//      else if(invokeExpr.symbol.isInstanceOf[ChainExpr]){
//        var chain = invokeExpr.symbol.asInstanceOf[ChainExpr]
//        if(chain.list.size <2) throw ParamLengthMismatchException(chain.list)
//        var first = chain.list(0) //first
//        var last = chain.list(chain.list.size-1) //obj
//        expr = this.findExpr(caches, first)
//        if(expr == nil) throw ExprNotFoundException(first)
//        if(last.isInstanceOf[InvokeExpr]){ //e.g. a.b.c()
//          invokeExpr.params = last.asInstanceOf[InvokeExpr].params
//          for(i <- Range(1,chain.list.size)){
//            if(!expr.isInstanceOf[GraphExpr]) throw ExprTypeMismatchException(expr)
//            expr = expr.asInstanceOf[GraphExpr].getNode(chain.list(i))
//            if(expr == nil) throw ExprNotFoundException(first)
//          }
//        } else {
//          for(i <- Range(1,chain.list.size-1)){
//            if(!expr.isInstanceOf[GraphExpr]) throw ExprTypeMismatchException(expr)
//            expr = expr.asInstanceOf[GraphExpr].getNode(chain.list(i))
//            if(expr == nil) throw ExprNotFoundException(first)
//          }
//          chain.pointer = expr
//          return chain          
//        }
//      }
      else {
    	  expr = this.findExpr(caches, invokeExpr.symbol)
      }
      if(expr == nil) {
        //*********************primary function********************//
        if(invokeExpr.symbol == SymbolExpr("write") || invokeExpr.symbol == SymbolExpr("print")){
          println(evalListExpr(caches, ListExpr(invokeExpr.params)))
          return nil
        }
        if(invokeExpr.symbol == SymbolExpr("true")){
          return truexpr
        }
        if(invokeExpr.symbol == SymbolExpr("false")){
          return falsexpr
        }
        if(invokeExpr.symbol == SymbolExpr("if")){
          if(invokeExpr.params.size == 2){ //e.g. if(cond,expr)
            var ifExpr = IfExpr(invokeExpr.params(0))
            ifExpr.exprT = invokeExpr.params(1)
            return evalIfExpr(caches, ifExpr)
          } else if(invokeExpr.params.size == 3){ //e.g. if(cond,exprT,exprF)
          	var ifExpr = IfExpr(invokeExpr.params(0))
      			ifExpr.exprT = invokeExpr.params(1)
      			ifExpr.exprF = invokeExpr.params(2)
      			return evalIfExpr(caches, ifExpr)
          } else {
            throw ParamLengthMismatchException(invokeExpr)
          }
        }
        if(invokeExpr.symbol == SymbolExpr("for")){ //e.g. for(cond,expr)
          var forExpr = ForExpr(invokeExpr.params(0))
          forExpr.expr = invokeExpr.params(1)
          return evalForExpr(caches, forExpr)
        }
        if(invokeExpr.symbol == SymbolExpr("fromClass")){
          return evalFromClassExpr(caches, invokeExpr.params(0))
        }
        if(invokeExpr.symbol == SymbolExpr("return")){ //e.g. (return rst)
          return ReturnExpr(evalListExpr(caches, ListExpr(invokeExpr.params)))
        }
        //****************************************************************//
        
        throw ExprNotFoundException(invokeExpr.symbol)
      }
      if(invokeExpr.params == null) return expr //e.g. a not a()
      if(!expr.isInstanceOf[GraphExpr]) throw ExprNotCallableException(expr)
      //find definition
      val graph = expr.asInstanceOf[GraphExpr]
      if(graph.params.length != invokeExpr.params.length){
        throw ParamLengthMismatchException(graph)
      }
      var invokeParam = evalListExpr(caches, ListExpr(invokeExpr.params))
      if(invokeExpr.params.size != 1){ //means 1 evalListExpr will return it's value directly
    	  var paramMap = graph.params.zip(invokeParam.asInstanceOf[ListExpr].elems).toMap
			  graph.nodes.put(parambinding, ParamBindingMap(paramMap)) //param and arg binding
      } else {
        //var paramMap = Map[Expr,Expr](graph.params(0)->invokeParam)
        graph.nodes.put(parambinding, ParamBindingMap(Map[Expr,Expr](graph.params(0)->invokeParam))) //param and arg binding
      }
      
      val rst = graph.eval()
      graph.nodes.put(parambinding, nil) //Removing the binding between the parameters and the arguments
      rst
  }
  
  def evalOperatorExpr(caches:scala.collection.mutable.Map[Expr,Expr],operator:OperatorExpr):Expr = {
    logger.info(this, "evalOperatorExpr", List(caches,operator))
    var left = operator.left
    var right = operator.right
    //get expr
    
    var leftExpr = evalExpr(caches,left)
    var rightExpr = evalExpr(caches,right)
    var pair = (leftExpr,rightExpr)
    operator.op match {
  	  case SymbolExpr("+") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => NumberExpr(pair1.value + pair2.value)
  	      case (pair1:StringExpr,pair2:StringExpr) => StringExpr(pair1.value.concat(pair2.value))
  	      case (_,_) => {
            throw UnsupportedOperandException(operator)
          }
  	    }
  	  }
  	  case SymbolExpr("-") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => NumberExpr(pair1.value - pair2.value)
  	      case (_,_) => {
            throw UnsupportedOperandException(operator)
          }
  	    }
  	  }
  	  case SymbolExpr("*") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => NumberExpr(pair1.value * pair2.value)
  	      case (_,_) => {
            throw UnsupportedOperandException(operator)
          }
  	    }
  	  }
  	  case SymbolExpr("/") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => NumberExpr(pair1.value / pair2.value)
  	      case (_,_) => {
            throw UnsupportedOperandException(operator)
          }
  	    }
  	  }
  	  case SymbolExpr("%") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => NumberExpr(pair1.value % pair2.value)
  	      case (_,_) => {
            throw UnsupportedOperandException(operator)
          }
  	    }
  	  }
  	  case SymbolExpr("++") => {
  	    pair match {
  	      case (pair1:NumberExpr,nil) => {
  	        pair1.value = pair1.value+1
  	        NumberExpr(pair1.value) 
  	      }
  	      case (_,_) => {
  	        throw UnsupportedOperandException(operator)
  	      }
  	    }
  	  }
  	  case SymbolExpr("--") => {
  	    pair match {
  	      case (pair1:NumberExpr,nil) => {
  	        pair1.value = pair1.value - 1
  	        NumberExpr(pair1.value)
  	      }
  	      case _ => {
  	        throw UnsupportedOperandException(operator)
  	      }
  	    }
  	  }
  	  //Relation operator
  	  case SymbolExpr("==") => {
  	    pair match {
  	      case(pair1:NumberExpr,pair2:NumberExpr) => if(pair1.value == pair2.value) truexpr else falsexpr
  	      case(pair1:StringExpr,pair2:StringExpr) => if(pair1.value == pair2.value) truexpr else falsexpr
  	      case _ => falsexpr
  	    }
  	  }
  	  case SymbolExpr("!=") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => if(pair1.value != pair2.value) truexpr else falsexpr
  	      case (pair1:StringExpr,pair2:StringExpr) => if(pair1.value != pair2.value) truexpr else falsexpr
  	      case _ => falsexpr
  	    }
  	  }
  	  case SymbolExpr(">") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => if(pair1.value > pair2.value) truexpr else falsexpr
  	      case (pair1:StringExpr,pair2:StringExpr) => if(pair1.value > pair2.value) truexpr else falsexpr
  	      case _ => falsexpr
  	    }
  	  }
  	  case SymbolExpr(">=") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => if(pair1.value >= pair2.value) truexpr else falsexpr
  	      case (pair1:StringExpr,pair2:StringExpr) => if(pair1.value >= pair2.value) truexpr else falsexpr
  	      case _ => falsexpr
  	    }
  	  }
  	  case SymbolExpr("<") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => if(pair1.value < pair2.value) truexpr else falsexpr
  	      case (pair1:StringExpr,pair2:StringExpr) => if(pair1.value < pair2.value) truexpr else falsexpr
  	      case _ => falsexpr
  	    }
  	  }
  	  case SymbolExpr("<=") => {
  	    pair match {
  	      case (pair1:NumberExpr,pair2:NumberExpr) => if(pair1.value <= pair2.value) truexpr else falsexpr
  	      case (pair1:StringExpr,pair2:StringExpr) => if(pair1.value <= pair2.value) truexpr else falsexpr
  	      case _ => falsexpr
  	    }
  	  }
  	  //Logical operator
  	  case SymbolExpr("&&") => {
  	    if(pair._1 == nil || pair._2 == nil
  	        || pair._1 == falsexpr || pair._2 == falsexpr
  	        || pair._1 == StringExpr("false") || pair._2 == StringExpr("false")
  	        || pair._1 == StringExpr("") || pair._2 == StringExpr("")
  	        || pair._1 == NumberExpr(0)|| pair._2 == NumberExpr(0)){
  	      falsexpr
  	    } else {
  	      truexpr
  	    } 
  	  }
  	  case SymbolExpr("||") => {
  	    if(pair._1 != nil 
  	        && pair._1 != falsexpr
  	        && pair._1 != StringExpr("false") 
  	        && pair._1 != StringExpr("") 
  	        && pair._1 != NumberExpr(0)
  	        || pair._2 != nil 
  	        && pair._2 != falsexpr
  	        && pair._2 != StringExpr("false") 
  	        && pair._2 != StringExpr("") 
  	        && pair._2 != NumberExpr(0)){
  	      truexpr
  	    } else {
  	      falsexpr
  	    }
  	  }
  	  case SymbolExpr("!") => {
  	    if(pair._2 != nil) throw SyntaxException(pair)
  	    if(pair._1 == nil 
  	        || pair._1 == falsexpr 
  	        || pair._1 == StringExpr("false") 
  	        || pair._1 == StringExpr("") 
  	        || pair._1 == NumberExpr(0)) truexpr else falsexpr
  	  }
//  	  case SymbolExpr("=") => {  // a = b
//  	    if(left.isInstanceOf[SymbolExpr]){
//  	      var symbol = left.asInstanceOf[SymbolExpr]
//  	      if(right.isInstanceOf[GraphExpr]){ //e.g. a = {...}
//  	        var graph = right.asInstanceOf[GraphExpr]
//  	        graph.nodes.put(closure, ClosureMap(caches)) //closure
//  	        caches.put(symbol, graph)
//  	      } else if(caches.contains(symbol)){ //assigned a new value to expr
//  	        caches.put(symbol, rightExpr)
//  	      } else if(this.contains(symbol)){ 
//  	        this.setNode(symbol, rightExpr)
//  	      }  else { //create a new expr
//  	        caches.put(symbol, rightExpr)
//  	      }
//  	      
//  	    } else if(left.isInstanceOf[DotExpr]){ //e.g. a.b = 3
//  	      var dotExpr = left.asInstanceOf[DotExpr]
//  	      dotExpr.parent.asInstanceOf[GraphExpr].nodes.put(dotExpr.expr2, rightExpr)
//  	    } else {
//  	      throw UnsupportedOperandException(left)
//  	    }
//  	    rightExpr
//  	  }
  	  case SymbolExpr("~") => {
  	    left = right
  	    left
  	  }
  	  case SymbolExpr("nil") => { //e.g. sym = 3,sym; means return an expr represent by sym
  	    if(left == nil && right.isInstanceOf[SymbolExpr]){
  	    	rightExpr
  	    } else {
  	      throw UnsupportedOperatorException(operator)
  	    }
  	  }
  	  case _ => {
  	    throw UnsupportedOperandException(operator.op)
  	    nil
  	  }
    }
  }
  
  /**
   * =
   */
  def evalAssignExpr(caches:scala.collection.mutable.Map[Expr,Expr],assign:AssignExpr):Expr = {
    logger.info(this, "evalAssignExpr", List(caches,assign))
    if(assign.left.isInstanceOf[SymbolExpr]){ //e.g. a = ...
      var symbol = assign.left.asInstanceOf[SymbolExpr]
      if(assign.right.isInstanceOf[GraphExpr]){ //e.g. a = {...}
        var graph = assign.right.asInstanceOf[GraphExpr]
        graph.nodes.put(closure, ClosureMap(caches)) //closure
        caches.put(symbol, graph)
      } else if(caches.contains(symbol)){ //assigned a new value to expr
        caches.put(symbol, evalExpr(caches, assign.right))
      } else if(this.contains(symbol)){ 
        this.setNode(symbol, evalExpr(caches, assign.right))
      }  else { //create a new expr
        caches.put(symbol, evalExpr(caches, assign.right))
      }
      
    } else if(assign.left.isInstanceOf[DotExpr]){ //e.g.  a.b = 3
      var dotExpr = assign.left.asInstanceOf[DotExpr]
      evalDotExpr(caches, dotExpr) //eval parent node
      if(dotExpr.parent.isInstanceOf[GraphExpr]){ //a{}
    	  dotExpr.parent.asInstanceOf[GraphExpr].nodes.put(dotExpr.expr2, evalExpr(caches, assign.right))
      } else if(dotExpr.parent.isInstanceOf[AssignExpr]){ //a = {}
        if(dotExpr.parent.asInstanceOf[AssignExpr].right.isInstanceOf[GraphExpr]) throw SyntaxException(dotExpr)
        dotExpr.parent.asInstanceOf[AssignExpr].right.asInstanceOf[GraphExpr].nodes.put(dotExpr.expr2, evalExpr(caches, assign.right))
      } else if(dotExpr.parent.isInstanceOf[ListExpr]){ //e.g. [1,2,3]
        var index = evalExpr(caches, dotExpr.expr2)
        if(!index.isInstanceOf[NumberExpr]) throw SyntaxException("Want Number,found: " + index)
        dotExpr.parent.asInstanceOf[ListExpr].elems(index.asInstanceOf[NumberExpr].value.intValue()) = evalExpr(caches, assign.right)
      }
    } else {
      throw UnsupportedOperandException(assign)
    }
    nil
  }
  
}